/*
 * Title:        CloudScheduler Toolkit
 * Description:  a Toolkit for Modeling and Simulation of Job Scheduling and Resource Provisioning in Cloud System
 * Licence:      GPL - http://www.gnu.org/copyleft/gpl.html
 * Author:       Fuhui Wu
 *
 * Copyright (c) 2013-2014, The National University of Defense Technology, China
 */

package org.nudt.jCloud.resourceManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.nudt.jCloud.infrastructure.Cluster;
import org.nudt.jCloud.infrastructure.Host;
import org.nudt.jCloud.infrastructure.Slot;
import org.nudt.jCloud.infrastructure.SlotType;
import org.nudt.jCloud.simulation.Framework;
import org.nudt.jCloud.simulation.SimEntity;
import org.nudt.jCloud.simulation.VirtSlot;
import org.nudt.jCloud.simulation.VirtSlotAlloc;

public abstract class ResManager extends SimEntity{
	private List<Host> hostList;
	private List<Framework> frwkList;
	
	public ResManager(String name, Cluster cluster) {
		super(name);
		if(cluster == null){
			setHostList(new ArrayList<Host>());
		}else{
			setHostList(cluster.getHostList());			
		}
		frwkList = new ArrayList<Framework>();
	}
	
	public void reset(){
		setId(-1);
		for(int i=0; i<hostList.size(); ++i){
			hostList.get(i).reset();
		}
		frwkList.clear();
	}
	
	public void addHost(Host host){
		getHostList().add(host);
	}
	
	public List<Slot> provideSlots(SlotType slotType, int slotNum){
		List<Slot> slots = new ArrayList<Slot>();
		for(int j=0; j<getHostList().size(); ++j){
			Host host = getHostList().get(j);
			while(true){
				Slot slot = host.provideSlot(slotType);
				if(slot == null){
					break;
				}else{
					slots.add(slot);
					if(slots.size()>=slotNum){
						return slots;
					}
				}
			}
		}
		return slots;		
	}
	
	/**
	 * 
	 * @param virtSlotAlloc
	 * @param slotType
	 * @param slotNum
	 * @param virtSlotAllocList The already allocated virtSlotAllocs in this job scheduler.
	 * @return
	 */
	public List<VirtSlot> provideVirtSlots(VirtSlotAlloc virtSlotAlloc,
			SlotType slotType, int slotNum, List<VirtSlotAlloc> virtSlotAllocList){
		List<VirtSlot> freeVirtSlotList = new ArrayList<VirtSlot>();
		for(int i=0; i<getHostList().size(); ++i){
			Host host = getHostList().get(i);
			/**
			 * Using "List<VirtSlot> busyVirtSlotList = virtSlotAlloc.getVirtSlotSet().get(host);"
			 * is wrong, because of the competing of VirtSlot list.
			 */
			List<VirtSlot> busyVirtSlotList = new ArrayList<VirtSlot>();
			if(virtSlotAlloc.getVirtSlotSet().containsKey(host)){
				for(int j=0; j<virtSlotAlloc.getVirtSlotSet().get(host).size(); ++j){
					busyVirtSlotList.add(virtSlotAlloc.getVirtSlotSet().get(host).get(j));
				}				
			}
			for(VirtSlotAlloc allocatedVirtSlotAlloc : virtSlotAllocList){
				if(allocatedVirtSlotAlloc.getVirtSlotSet().containsKey(host)){
					for(VirtSlot allocatedVirtSlot : allocatedVirtSlotAlloc.getVirtSlotSet().get(host)){
						busyVirtSlotList.add(allocatedVirtSlot);
					}
				}
			}
			while(true){
				VirtSlot virtSlot = host.provideVirtSlot(slotType, busyVirtSlotList);
				if(virtSlot != null){
					busyVirtSlotList.add(virtSlot);
					freeVirtSlotList.add(virtSlot);
					if(freeVirtSlotList.size() == slotNum){
						return freeVirtSlotList;
					}
				}else{
					break;
				}
			}
		}
		return freeVirtSlotList;
	}
	
	public void releaseSlot(Slot slot){
		slot.getHost().releaseSlot(slot);
	}

	public void releaseSlot(List<Slot> slotList){
		for(int i=0; i<slotList.size(); ++i){
			releaseSlot(slotList.get(i));
		}
	}
	
	public void sortFrwkBySlotNumDec(){
		Collections.sort(getFrwkList(), new Framework.SortBySlotNumDec());
	}
	
	public void sortFrwkByStolenNumDec(){
		Collections.sort(getFrwkList(), new Framework.SortByStolenNumDec());
	}
			
	public void registerFrwk(Framework frwk){
		frwk.setId(frwkList.size());
		frwkList.add(frwk);
	}

	@Override
	public void startEntity(){
		
	}
		
	/**
	 * @return the frwkList
	 */
	public List<Framework> getFrwkList() {
		return frwkList;
	}

	/**
	 * @param frwkList the frwkList to set
	 */
	public void setFrwkList(List<Framework> frwkList) {
		this.frwkList = frwkList;
	}

	public List<Host> getHostList() {
		return hostList;
	}

	public void setHostList(List<Host> hostList) {
		this.hostList = hostList;
	}

}
